from abc import abstractmethod
from typing import List

from sam.util.dbUtil import DB
from sam.util.esUtil import EsConfig, EsUtil


class EsSyncUtil(object):
    def __init__(self, es_config: EsConfig, db: DB):
        super().__init__()
        self.es = EsUtil(es_config)
        self.db = db
        self.logger = self.es.logger

    @abstractmethod
    def get_update_list_from_db(self) -> List[dict]:
        pass

    @abstractmethod
    def pre_handle_db_query_result_list(self, pre_result_list: List[dict]) -> List[dict]:
        pass

    def update_by_db(self
                     , batch_size: int = 5000
                     , optional: str = "Update"
                     , is_only_print_sql: bool = False
                     , id_column: str = "id"
                     ):

        pre_result_list = self.get_update_list_from_db()
        if pre_result_list:
            self.logger.info(f"读取数据库完成 共 {len(pre_result_list)} 条 需要进行")
            result_list = self.pre_handle_db_query_result_list(pre_result_list)
            if result_list:
                self.logger.info(f"对从数据库中读取的结果预处理完成 共 {len(pre_result_list)} 条需要更新到Es中")
                if "Update" == optional:
                    self.es.batch_update_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
                elif "Delete" == optional:
                    self.es.batch_delete_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
                elif "Insert" == optional:
                    self.es.batch_insert_or_update_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
                else:
                    msg = f"只支持[Update, Delete, Insert]操作, 不支持当前操作{optional}"
                    raise RuntimeError(msg)
        else:
            self.logger.info(f"读取数据库完成, 但没有获取到 需要处理的数据.")

    @abstractmethod
    def get_update_list_from_file(self) -> List[dict]:
        pass

    @abstractmethod
    def pre_handle_file_read_result_list(self, pre_result_list: List[dict]) -> List[dict]:
        pass

    def update_by_file(self, batch_size: int = 5000, optional: str = "Update", is_only_print_sql: bool = True,
                       id_column: str = "id"):
        pre_result_list = self.get_update_list_from_file()
        if pre_result_list:
            self.logger.info(f"读取 文件 完成 共 {len(pre_result_list)} 条")
            result_list = self.pre_handle_file_read_result_list(pre_result_list)
            if result_list:
                self.logger.info(f"对从 文件 中读取的结果预处理完成 共 {len(pre_result_list)} 条需要更新到Es中")
                if "Update" == optional:
                    self.es.batch_update_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
                elif "Insert" == optional:
                    self.es.batch_insert_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
                else:
                    self.es.batch_insert_or_update_es(
                        result_list
                        , is_only_print_sql=is_only_print_sql
                        , batch_size=batch_size
                        , id_column=id_column
                    )
        else:
            self.logger.info(f"读取数据库完成, 但没有获取到 需要处理的数据.")


class File2Es(EsSyncUtil):

    def get_update_list_from_db(self) -> List[dict]:
        pass

    def pre_handle_db_query_result_list(self, pre_result_list: List[dict]) -> List[dict]:
        pass

    @abstractmethod
    def get_update_list_from_file(self) -> List[dict]:
        pass

    @abstractmethod
    def pre_handle_file_read_result_list(self, pre_result_list: List[dict]) -> List[dict]:
        pass
